import Blender
import os
import struct
from Blender import *
from Blender import Lamp
from Blender.Scene import Render
from Blender.Draw import *
from Blender.BGL import *
from Blender import Registry
from Blender import Text

from math import *
	
#globals

#get the root directory that the current file is in
#we'll write the muray files there.  
path = Blender.Get('filename')
tokens = path.split('\\')
fileName = tokens.pop();
file = fileName.split('.')
fileName = file[0]

path =''
for i in tokens:
	path = path + i + '\\'  


def export():
	#open a file to export to
	f = open(path + fileName + '.mra','wb')
	s = open(path + fileName + '.mrb','wb')
	
	f.write('muRay scene description\n')
	f.write(' 	                                                                                                                                                                ')
	def writeln(out):
		f.write(out + '\n')
	
	def fmt(input):
		return '%5.5f' %input

	def point_by_matrix(p, m):
		return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0] + m[3][0],
		p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1] + m[3][1],
		p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2] + m[3][2]]
	def vector_by_matrix(p, m):
  		return [p[0] * m[0][0] + p[1] * m[1][0] + p[2] * m[2][0],
        p[0] * m[0][1] + p[1] * m[1][1] + p[2] * m[2][1],
        p[0] * m[0][2] + p[1] * m[1][2] + p[2] * m[2][2]]	
	
	def contain(min, max, point):
		for v in point:
			if v[0] < min[0]:
				min[0] = v[0]
			if v[1] < min[1]:
				min[1] = v[1]
			if v[2] < min[2]:
				min[2] = v[2]
			if v[0] > max[0]:
				max[0] = v[0]
			if v[1] > max[1]:
				max[1] = v[1]
			if v[2] > max[2]:
				max[2] = v[2]			
	def containSphere(min,max,sphere):
		radius = sphere.getSize()[0]
		if min[0] > sphere.LocX-radius:
			min[0] = sphere.LocX-radius
		if min[1] > sphere.LocY-radius:
			min[1] = sphere.LocY-radius
		if min[2] > sphere.LocZ-radius:
			min[2] = sphere.LocZ-radius
		if max[0] < sphere.LocX+radius:
			max[0] = sphere.LocX+radius
		if max[1] < sphere.LocY+radius:
			max[1] = sphere.LocY+radius
		if max[2] < sphere.LocZ+radius:
			max[2] = sphere.LocZ+radius
		

	#Grab the scene
	scn = Scene.GetCurrent()
	context = scn.getRenderingContext()
	obj = Blender.Object.Get()
	
	#export general scene data


	#background color
	w=Blender.World.Get()

	scene = Blender.Scene.GetCurrent().getChildren()

	writeln('')
	
	#create the baked textures list
	baked_maps=[]
	
	#create a materials list
	material_array =[]
	materials = Material.get()
	for m in materials:
		
		refFile = "NULL";
		textureFile = "NULL";
		alphaFile = "NULL";
		normalFile = "NULL";
		emitFile = "NULL";
		specFile = "NULL";
	    							
		for mtex in m.getTextures():
			if mtex: 				
				#check if there is an image
				if mtex.tex.type == Texture.Types.IMAGE:
					print mtex.tex.image.getFilename()
					#map to color
					if mtex.mapto == Texture.MapTo.COL:
						textureFile = mtex.tex.image.getFilename()
					if mtex.mapto == Texture.MapTo.ALPHA:
						alphaFile = mtex.tex.image.getFilename()		
					if mtex.mapto == Texture.MapTo.NOR:
						normalFile = mtex.tex.image.getFilename()			
					if mtex.mapto == Texture.MapTo.EMIT:
						emitFile = mtex.tex.image.getFilename()
					if mtex.mapto == Texture.MapTo.REF:
						refFile = mtex.tex.image.getFilename()			
					if mtex.mapto == Texture.MapTo.SPEC:
						specFile = mtex.tex.image.getFilename()
		
		print m.getDiffuseShader()
		material_array.append(m.getName())	
		writeln('shad=' + str(m.rgbCol) + '|' +str(m.getRayMirr()) + '|' + str(m.getHardness()) +
			 '|' + str(m.getAlpha()) +'|'+ str(m.getIOR()) +'|'+
				str(m.getSpec())+'|'+ str(m.getEmit())+'|' + str(m.getRef()) + '|' +
				str(m.getDiffuseShader()) +'|' + str(m.getSpecShader()) + '|' +
				str(m.getSpecCol()) +'|' +
				str(textureFile) + '|' + str(alphaFile) + '|' + 
				str(normalFile)	+ '|' + str(emitFile)+'|' + str(refFile) + '|' + 
				str(specFile)

				)	

	#while looping through the scene, we will need to collect the maximum
	#extents of the scene.  These will be written to the head of the file
	#after all mesh objects have been measure
	min = [1e300,1e300,1e300];
	max = [-1e200,-1e300,-1e300];
	numObjects = 0

	for obj in scene:

		if obj.getType() == 'Camera':
			cam_mat = obj.getMatrix('worldspace')
			print 'Exporting camera'

			height = context.imageSizeY()
			width = context.imageSizeX()
			lens = obj.getData().lens			
 			fov = lens;	
			writeln('cam=' + str(camType.val) + 
				'['+str(cam_mat[0][0]) + ',' + str(cam_mat[0][1]) + ',' + str(cam_mat[0][2]) + ']' + '|' +
				'['+str(cam_mat[1][0]) + ',' + str(cam_mat[1][1]) + ',' + str(cam_mat[1][2]) + ']' + '|' +				
				'['+str(-cam_mat[2][0]) + ',' + str(-cam_mat[2][1]) + ',' + str(-cam_mat[2][2]) + ']' + '|' +
				'['+str(cam_mat[3][0]) + ',' + str(cam_mat[3][1]) + ',' + str(cam_mat[3][2]) + ']' + '|' +
				str(width) + ',' + str(height) + ']' + '|' +
				str(fov) + ',' + str(fov) + ']' + str(obj.getData().getClipStart()) + '|' + str(camRadiusSlider.val) + '|' 
				)
	
		elif obj.getType() == 'Lamp':
			print 'Exporting Lamp'	
			l=Lamp.Get(obj.getName())
			m = obj.getMatrix()
			if l.getType() == 0:	
				#lamp=location,color,size,energy for a lamp
				writeln('lamp=[' + str(obj.getLocation()) + ']|['+ str(3*l.getEnergy()*l.col[0]) +','+ str(3*l.getEnergy()*l.col[1]) + ','+str(3*l.getEnergy()*l.col[2]) )
			elif l.getType() == 1:
				#sun=location,color,energy,direction
				print 'Exporting the sun'
				
				vec = vector_by_matrix([0,0,1],m)
				print str(vec)
				writeln('sun=['+ str(vec) + ']|[' + str(3*l.getEnergy()*l.col[0]) +','+ str(3*l.getEnergy()*l.col[1]) + ','+str(3*l.getEnergy()*l.col[2]) )
				

		elif obj.getType() =='Surf':
			material_index = material_array.index(obj.getName())

			containSphere(min,max,obj)

			writeln('sphere=[' + str(obj.getLocation()) +
					 ']|['+ str(obj.size[0]) + ']|['+ str(material_index))
	
		elif obj.getType() == 'Mesh':
			
			#get standard mesh data
			m = NMesh.GetRawFromObject(obj.getName())
			mat = obj.getMatrix('worldspace')
						
			#for every mesh, we dump a list of vertices
			numverts = len(m.verts)
			numTris = 0			
			print 'verts ' + str(numverts)		 
			writeln('numverts=' + str(numverts))			
					
			for i in range(numverts):			
				x,y,z = point_by_matrix(m.verts[i].co,mat)
				writeln('v=' + fmt(x) + '|' + fmt(y) +'|' + fmt(z))
			    
			
			#iterate through faces - then split faces into triangles
			faces = m.faces
			
			#last
			
			lastUVTexture = 0
			lastidx = 0;
			
			for fa in faces:
				
				#each face may have an image
				if str(fa.image) == 'None':
					idx = -1
				else:
					#is this image the last one?
					if lastUVTexture == fa.image:
						
						idx = lastidx
					
					#different texture, have we seen it before?
					try:
						idx = baked_maps.index(fa.image)
					#create new entry	
					except ValueError:
						baked_maps.append(fa.image)	
						idx = baked_maps.index(fa.image)
					
					lastUVTexture = fa.image
					lastidx = idx;
						
				
				if len(fa.v) == 3: 
					numTris += 1
					numObjects+=1
					
					#check for uv coordinates
					#there has got to be a better way to do this
					if len(fa.uv) == 0:
						zers=[0,0];
						fa.uv = [zers,zers,zers];
										
				
					trans = [point_by_matrix(fa.v[0].co,mat),point_by_matrix(fa.v[1].co,mat),point_by_matrix(fa.v[2].co,mat)]
					contain(min,max,trans)
					
					writeln('t=' + 
					str(fa.v[0].index) + '|' + str(fa.v[1].index) + '|' + str(fa.v[2].index) + '|' + 
					str(material_array.index(m.materials[fa.mat].getName())) + '|' +
					fmt(fa.uv[0][0]) + '|' + fmt(1-fa.uv[0][1]) + '|' + fmt(fa.uv[1][0]) + '|' + fmt(1-fa.uv[1][1]) + '|' + fmt(fa.uv[2][0]) + '|' + fmt(1-fa.uv[2][1]) + '|' + 
					str(idx)
					)
			
				else:
					numTris += 2
					numObjects+=2
					
					#check for uv coordinates
					#there has got to be a better way to do this
					if len(fa.uv) == 0:
						zers=[0,0];
						fa.uv = [zers,zers,zers,zers];
		
											
					try:
						trans = [point_by_matrix(fa.v[0].co,mat),point_by_matrix(fa.v[1].co,mat),point_by_matrix(fa.v[2].co,mat)]
						contain(min,max,trans)

						writeln('t=' + 
						str(fa.v[0].index) + '|' + str(fa.v[1].index) + '|' + str(fa.v[2].index) + '|' + 
						str(material_array.index(m.materials[fa.mat].getName())) + '|' +
						fmt(fa.uv[0][0]) + '|' + fmt(1-fa.uv[0][1]) + '|' + fmt(fa.uv[1][0]) + '|' + fmt(1-fa.uv[1][1]) + '|' + fmt(fa.uv[2][0]) + '|' + fmt(1-fa.uv[2][1]) + '|' + 
						str(idx)
						)
	
						trans = [point_by_matrix(fa.v[2].co,mat),point_by_matrix(fa.v[3].co,mat),point_by_matrix(fa.v[0].co,mat)]
						contain(min,max,trans)
						
						writeln('t=' + 
						str(fa.v[2].index) + '|' + str(fa.v[3].index) + '|' + str(fa.v[0].index) + '|' + 
						str(material_array.index(m.materials[fa.mat].getName())) + '|' +
						fmt(fa.uv[2][0]) + '|' + fmt(1-fa.uv[2][1]) + '|' + fmt(fa.uv[3][0]) + '|' + fmt(1-fa.uv[3][1]) + '|' + fmt(fa.uv[0][0]) + '|' + fmt(1-fa.uv[0][1]) + '|' + 
						str(idx)
						)
						
						
					except:
						print 'caught quad exception on ' + str(fa)	

			
			
	#if the background is set pass that in, else pass color
	if Background.val:
		writeln('bgimage=' + str(BackgroundText.val))
	else:
		writeln('bgcolor=' + str(w[0].getHor()))
	
	#write out the baked textures

	for tex in baked_maps:
		s.write('b=' + str(tex) + '\n') 

	#done with the scene	
	f.close
	s.close
	
def render():
	spawnPath = path + fileName
	os.spawnl(os.P_NOWAIT,executable,'foo ' + path + ' ' + fileName)
	#os.spawnl(os.P_NOWAIT,"/home/sheemwaza/base/optimized/src/base","monkey","/home/sheemwaza/out.mra")
	#retcode=Popen(["/home/sheemwaza/base/src/base","/home/sheemwaza/out.mra"]).pid
	print 'no op'

mSampleSlider = Create(0)
camRadiusSlider = Create(1)
imageSamples = Create(1)
shadowSamples = Create(4)
muonSlider = Create(0)
Muon = Create(0)
BackgroundText = Create('using background color')
Background = Create(0)
numSample = Create(4)
hemiToggle = Create(0)
camType = Create(1)
iCacheToggle = Create(0)
samplerWindow = Create(1)
GIWindow = Create(0)
partOutput = Create(0)
bounce = Create(0)	
filterWidth = Create(0)
jitter = Create(0)
sbackground = Create(1)

materialsDrop = Create(0)
	
def draw():
	global mSampleSlider, muonSlider, Muon,BackgroundText
	global Background, numSample, hemiToggle, bounce, ExitButton, iCacheToggle
	global Button2, camType, exportButton
	global imageSamples, shadowSamples
	global camRadiusSlider
	global samplerWindow, GIWindow
	global partOutput
	global filterWidth, jitter
	global sbackground	
		


	glClearColor(1.0, 1.0, 1.0, 0.0)
	glClear(GL_COLOR_BUFFER_BIT)

	leftMargin = 10;
	bottomMargin = 15;
	columnWidth = 170;
	buttonWidth = columnWidth - leftMargin;
	columnHeight = 35;
	buttonHeight = columnHeight - bottomMargin;

	#always display these buttons

	Button('Exit', 3, leftMargin, 5, buttonWidth, buttonHeight, '')
	Button('Export', 1, leftMargin+columnWidth,5, buttonWidth, buttonHeight, '')
	Button('Render', 2, leftMargin+ 2*columnWidth, 5, buttonWidth, buttonHeight, '')
	
	camType = Menu('Camera Model%t|Perspective %x1|Spherical %x2|Architecture %x3|DOF %x4', 5, leftMargin, 5*columnHeight, buttonWidth, buttonHeight, camType.val, 'Select which type of camera to use.')
	imageSamples = Slider('Image', 11, leftMargin , 6*columnHeight, buttonWidth, buttonHeight, imageSamples.val, 1, 20, imageSamples.val,'')
	shadowSamples = Slider('Shadow', 12, leftMargin + columnWidth, 6*columnHeight, buttonWidth, buttonHeight, shadowSamples.val, 1, 20, 1,'')	

	
	#these are the GI settings
	#Background = Toggle('Set Background', 7,leftMargin, 4*columnHeight, buttonWidth, buttonHeight, Background.val, '')
		
	   
	sbackground = Menu('Background%t|Uniform %x1|CIE Clear Sky %x2|CIE Overcast %x3|Sky Model %x4', 102, leftMargin, 3*columnHeight, buttonWidth, buttonHeight,sbackground.val, 'Set Background')
	

	numSample = Slider('Samples', 6, leftMargin + columnWidth, 2*columnHeight, buttonWidth, buttonHeight,numSample.val, 1, 64, 4, 'The number of hemisphere samples.')

	bounce = Slider('Bounce', 0, leftMargin + 2 * columnWidth, 2*columnHeight, buttonWidth, buttonHeight, bounce.val, 1, 5, 0,'')	
		
	if Background.val == 1:
		BackgroundText = String('', 6, leftMargin + columnWidth, 4*columnHeight, buttonWidth, buttonHeight, BackgroundText.val, 512, '')
	
	if camType.val == 4:
		camRadiusSlider = Slider('Radius', 0, leftMargin + columnWidth, 5*columnHeight, buttonWidth, buttonHeight, camRadiusSlider.val, 1, 20, 1,'')

				
def setBackground(fname):
	print fname
	BackgroundText.val=fname

def event(evt, val):
	if (evt== QKEY and not val): Exit()

def bevent(evt):


	if evt == 7: #setBackground
		Blender.Window.FileSelector(setBackground,'OPEN FILE')

	elif evt == 10:
					
		print 'Materials'
		Blender.Redraw()
			
	elif evt == 3: #ExitButton
		Exit()

	elif evt == 2: #Button2
		export()
		render()

	elif evt == 1: #exportButton
		export()
				
	else:
		Blender.Redraw()
	
Register(draw, event, bevent)